home *** CD-ROM | disk | FTP | other *** search
- /*
- copyright © 1991-1994 Apple Computer Inc. All rights reserved.
-
- NewApp.c
- This file contains all new API implementations for the ImageWriter driver.
-
- Modification history
- 3/19/91 TED New file today
- 04/23/91 Sam Weiss Changed Inherit to Forward
- 05/29/91 TED Added manual feed and faster mode support
- 12/20/93 dmh Sync'd with the shipping 1.0b3 GX driver.
- 12/22/93 dmh Added SD_DespoolPage, which handles image flipping. Marked routines.
-
- */
-
- #include <Memory.h>
- #include <QuickDraw.h>
- #include <Controls.h>
- #include <Errors.h>
- #include <ToolUtils.h>
- #include <Resources.h>
- #include <Packages.h>
- #include <PrintingDrivers.h>
- #include <PrintingMessages.h>
- #include <PrintingManager.h>
- #include <FixMath.h>
- #include <math routines.h>
- #include <math types.h>
- #include <Graphics Routines.h>
- #include <graphics libraries.h>
- #include <font library.h>
- #include <layout routines.h>
- #include <GXExceptions.h>
- #include <PrintingLibraries.h>
-
- #include "CommonDefines.h"
-
- extern long A5Size(void);
- extern void A5Init(void *);
-
- FourPicts *gFlippedPicts; // A pointer holding the PicHandles and flip setting
- // for our options dialog.
-
-
- /* ------------------------------------------------------------------------------------ */
- /* INTERNAL DEFINES */
- /* ------------------------------------------------------------------------------------ */
-
- // things this specific driver puts into the DTP config file
- #define kImageWriterConfigType 'ifig'
- #define kImageWriterConfigID (0)
- typedef struct
- {
- Boolean hasColorRibbon;
- Boolean hasSheetFeeder;
- Boolean isImageWriterII; // is this an ImageWriter II, or an older model?
- } ImageWriterConfigRecord, *ImageWriterConfigPtr, ** ImageWriterConfigHandle;
-
- /* Define special characters needed */
- #define ESCAPE (char) 27
-
- /* A record to hold a set margins command */
- typedef struct SetMarginsRecord
- {
- char cEscape; // ESCAPE character
- char cCommand; // Set Margins command character
- char cIndentDistance[4]; // number of dots to indent
- } SetMarginsRecord, *SetMarginsPtr;
- #define kSetMarginsCommand (char)'F' // ImageWriter II uses 'F' for tabbing
- #define kSetMarginsSize 6
-
- /* Define a record that can hold one scan line's worth of data, 1280 will
- only happen at 160 dpi. and 14 inch wide paper. */
- typedef struct ScanLineRecord
- {
- char cColorEscape; // ESCAPE character
- char cSetColorCommand; // Set color command
- char cColor; // The color
- char cEscape; // ESCAPE character
- char cCommand; // 'enter graphics' command
- char cLineLength[4]; // number of dots to print
- char iTheData[2240]; // Bits for the data, enough for one line's worth
- } ScanLineRecord, *ScanLinePtr;
- #define kGraphicsCommand (char)'G' /* graphics printing command */
- #define kRepeatGroup (char)'V' /* repeat group character */
- #define kSetColorCommand (char)'K' /* Set color command */
- #define kGroupSize 6 /* Size of one group header */
-
- #define kScanLineSize 3 /* NOTE: this is just the header size! */
-
- #define kStatusCommand "\033?" /* request device status/config */
-
- // Status flags for PAP status queries
- #define kColorRibbonBit 0
- #define kSheetFeederBit 1
- #define kPaperOutBit 2
- #define kCoverOpenBit 3
- #define kOffLineBit 4
- #define kPaperJamBit 5
- #define kPrinterFaultBit 6
- #define kHeadMovingBit 7
- #define kPrinterBusyBit 8
-
- #define kOutOfPaperMask ( (0x8000 >> kPaperJamBit) | (0x8000 >> kCoverOpenBit) | (0x8000 >> kOffLineBit) )
- #define kPrinterOfflineMask ( (0x8000 >> kOffLineBit) )
- #define kPrinterBusyMask ( (0x8000 >> kPrinterBusyBit) )
-
- //<FF>
- /* ------------------------------------------------------------------------------------ */
- /* INTERNAL ROUTINES */
- /* ------------------------------------------------------------------------------------ */
- void Long2Dec(long aLong, Ptr emitHere)
- /*
- Converts a long into an ASCII string, padded with leading zeros.
- */
- {
- char aString[10];
- short i, actualWidth, strLength;
-
- NumToString(aLong, aString);
-
- // Get the width of the string, check for being too small
- strLength = aString[0];
- actualWidth = strLength;
- if (actualWidth < 4)
- actualWidth = 4;
-
- // output the string, padding with the requested character
- strLength = actualWidth-strLength;
- for (i = 0; i < actualWidth; ++i)
- {
- *emitHere++ = (i < strLength)
- ? '0' : aString[(i+1)-(strLength)];
- }
-
- } // Long2Dec
-
-
-
- /*******************************************************************
- SetupFormatPanel sets up our format dialog panel, adding a
- default "flip settings" collection item to the format collection
- if there isn't already one. This collection item has the values
- we'll use to set up our panel's controls.
-
- ********************************************************************/
-
- OSErr SetupFormatPanel(short panelResID, gxFormat pageFormat)
- {
- OSErr err;
- long itemSize;
- gxPanelSetupRecord panelSetupRec;
- gxFlipPageHorizontalInfo hFlipInfo;
- gxFlipPageVerticalInfo vFlipInfo;
- FlipCollection flipSettings;
- short oldResFile;
-
- // Get the format collection and see if the GX page flip collection
- // items are present. If either is missing, we'll interpret that
- // as meaning "don't flip" in that direction. Store the resulting
- // flags in our panel settings structure.
-
- itemSize = sizeof(gxFlipPageHorizontalInfo);
-
- err = GetFmtCollectionItem(&hFlipInfo, &itemSize, gxFlipPageHorizontalTag,
- gxPrintingTagID, pageFormat);
-
- if (err) hFlipInfo.flipHorizontal = false;
-
- itemSize = sizeof(gxFlipPageVerticalInfo);
-
- err = GetFmtCollectionItem(&vFlipInfo, &itemSize, gxFlipPageVerticalTag,
- gxPrintingTagID, pageFormat);
-
- if (err)
- {
- vFlipInfo.flipVertical = false;
- err = noErr;
- }
-
- flipSettings.flipHorizontal = hFlipInfo.flipHorizontal;
- flipSettings.flipVertical = vFlipInfo.flipVertical;
-
- // Now do the actual panel set up.
-
- panelSetupRec.panelResId = panelResID; // Which panel resource?
- panelSetupRec.resourceRefNum = GXGetMessageHandlerResFile(); // Where is it?
- panelSetupRec.refCon = 0; // We don't use this.
- panelSetupRec.panelKind = gxDriverPanel; // This is a driver panel.
-
- err = GXSetupDialogPanel(&panelSetupRec);
- nrequire(err, Setup_Failed);
-
- gFlippedPicts = (FourPicts *) NewPtrSysClear(sizeof(FourPicts));
-
-
- // Set up the current flipping field in our data structure to reflect
- // the type of flipping that's currently set-- 0 = no flipping,
- // 1 = horizontal flipping, 2 = vertical flipping, 3 = horizontal and
- // vertical flipping. Based on the current flipping, mark the
- // appropriate dialog checkboxes.
-
- gFlippedPicts->curFlipping = hFlipInfo.flipHorizontal +
- 2 * (char) vFlipInfo.flipVertical;
-
-
- // Set up the current flipping field in our data structure to reflect
- // the type of flipping. When done, restore the original resource file
- // and exit.
-
- oldResFile = CurResFile();
- UseResFile(GXGetMessageHandlerResFile());
-
- gFlippedPicts->pict[0] = (PicHandle) Get1Resource('PICT', p_Normal);
- nrequire((err = ResError()), CouldNotLoadPict);
- DetachResource((Handle) gFlippedPicts->pict[0]);
- gFlippedPicts->pict[1] = (PicHandle) Get1Resource('PICT', p_HFlip);
- nrequire((err = ResError()), CouldNotLoadPict);
- DetachResource((Handle) gFlippedPicts->pict[1]);
- gFlippedPicts->pict[2] = (PicHandle) Get1Resource('PICT', p_VFlip);
- nrequire((err = ResError()), CouldNotLoadPict);
- DetachResource((Handle) gFlippedPicts->pict[2]);
- gFlippedPicts->pict[3] = (PicHandle) Get1Resource('PICT', p_HVFlip);
- nrequire((err = ResError()), CouldNotLoadPict);
- DetachResource((Handle) gFlippedPicts->pict[3]);
-
- CouldNotLoadPict:
- UseResFile(oldResFile);
-
- Setup_Failed:
-
- return err;
- }
-
-
- void TearDownFormatPanel(gxDialogResult theResult, gxFormat pageFormat)
- {
- char idx;
-
- if (theResult == gxOKSelected)
- SetFormatFlipping(gFlippedPicts->curFlipping, pageFormat);
-
- for (idx = 0; idx < 4; idx++)
- if (gFlippedPicts->pict[idx])
- DisposHandle((Handle) gFlippedPicts->pict[idx]);
- }
-
-
- //<FF>
- /* ------------------------------------------------------------------------------------ */
- Boolean PrinterHasColorRibbon(gxPrinter thePrinter)
- /*
- Returns true if the config file says that the printer is blessed with a color ribbon,
- false if it is a black and white ribbon.
- */
- {
- Boolean hasColor = true;
- Str32 deviceName;
- OSErr anErr;
- ImageWriterConfigHandle configHandle;
-
- // if not formatting to a particular device, assume color ribbon, for widest range of colorSpaces
- GXGetPrinterName(thePrinter, deviceName);
- if (deviceName[0] != 0)
- {
- // if we are going to a particular device, assume no color, as that is more common
- hasColor = false;
-
- anErr = GXFetchDTPData(deviceName, kImageWriterConfigType, kImageWriterConfigID, &(Handle)configHandle);
- if (anErr == noErr)
- {
- hasColor = (**configHandle).hasColorRibbon;
- DisposHandle((Handle) configHandle);
- }
- }
-
- return(hasColor);
-
- } // PrinterHasColorRibbon
-
-
- //<FF>
- /* ------------------------------------------------------------------------------------ */
- gxViewDevice NewDeviceResolutionViewDevice(void)
- /*
- This routine creates a viewDevice and gives it a scale factor in it's mapping
- appropriate for this device (144 dpi in the case of the IW)
- */
- {
- gxViewDevice vd;
-
- // create the viewDevices with a fake bitmap
- {
- gxShape tempBitmap;
- gxBitmap aBitmap;
-
- aBitmap.pixelSize = 1;
- aBitmap.rowBytes = 0;
- aBitmap.width = 0;
- aBitmap.height = 0;
- aBitmap.image = (char*)gxMissingImagePointer;
- aBitmap.space = gxNoSpace;
- aBitmap.set = nil;
- aBitmap.profile = nil;
-
- tempBitmap = GXNewBitmap(&aBitmap, nil);
- vd = GXNewViewDevice(gxScreenViewDevices, tempBitmap);
- GXDisposeShape(tempBitmap);
- }
-
- // setup a mapping for a 144 (2X) viewDevice
- {
- gxMapping vdMapping;
-
- ResetMapping(&vdMapping);
- ScaleMapping(&vdMapping, ff(2), ff(2), ff(0), ff(0));
-
- GXSetViewDeviceMapping(vd, &vdMapping);
- }
-
- return(vd);
-
- } // NewDeviceResolutionViewDevice
-
- //<FF>
- /* ------------------------------------------------------------------------------------ */
- Boolean JobIsBest(long *imagewriterOptions)
- /*
- Returns true if the current job is a final quality mode job, else returns false.
- Also, returns the imagewriter rendering options.
- */
- {
- Boolean isFinal;
- gxQualityInfo jobQualitySettings;
- long itemSize = sizeof(jobQualitySettings);
- OSErr status;
- Collection jobCollection;
-
- // cache the collection
- jobCollection = GXGetJobCollection(GXGetJob());
-
- // find out the info
-
- isFinal = false;
-
- status = GetCollectionItem(jobCollection,
- gxQualityTag, gxPrintingTagID,
- &itemSize, &jobQualitySettings);
-
- if ( (status == noErr) && (jobQualitySettings.currentQuality == (jobQualitySettings.qualityCount-1)) )
- isFinal = true;
-
- ncheck( status );
-
- // we default to super res
- *imagewriterOptions = kSuperRes;
- itemSize = sizeof(imagewriterOptions);
- status = GetCollectionItem(jobCollection,
- DriverCreator, 0,
- &itemSize, imagewriterOptions);
-
- // and return the job quality mode
- return(isFinal);
-
- } // JobIsBest
-
-
- //<FF>
- /* ------------------------------------------------------------------------------------ */
-
- OSErr DoTheQuery(unsigned short * statusReturn, Boolean papStatus)
- /*
- Returns in statusString the current status for the printer. Returns various
- errors from IO package if the printer's status could not be found.
- */
- {
- OSErr anErr = noErr;
- long statusLength; // status string size
- SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
-
- // default to a clear status
- *statusReturn = 0;
-
- // send the query
- if (papStatus)
- {
- char statusString[255]; // returned string
-
- // According to the old IW driver, sometimes it will return all of the bits
- // set. This is an error, but we can just try again.
- do {
- statusLength = 255;
- anErr = Send_GXGetDeviceStatus(nil, 0, statusString, &statusLength, nil);
- } while ( (anErr == noErr) && (statusString[0] == 0xFF) );
-
- // return the printer status bits in the PAP case
- *statusReturn = *(unsigned short*)&statusString[0];
- }
- else
- {
- char statusString[8]; // returned string
-
- if ((**hGlobals).isImageWriterII)
- {
- statusLength = 8; // max number of characters to get back
- anErr = Send_GXGetDeviceStatus(kStatusCommand, 2, statusString, &statusLength, "\p\n");
-
- if ( anErr == gxAioTimeout)
- {
- *statusReturn = kPrinterOfflineMask;
- anErr = noErr;
- }
- else
- {
- if (anErr == noErr)
- {
- // generate printer status bits in the serial case
- if (statusString[4] == 'C')
- *statusReturn |= 0x8000 >> kColorRibbonBit;
- if ( (statusString[5] == 'F') || (statusString[4] == 'F') )
- *statusReturn |= 0x8000 >> kSheetFeederBit;
- }
- }
- }
- }
-
- nrequire(anErr, Send_GXGetDeviceStatus);
-
- // FALL THROUGH EXCEPTION HANDLING
- Send_GXGetDeviceStatus:
-
- return(anErr);
-
- } // DoTheQuery
-
- //<FF>
- /* ------------------------------------------------------------------------------------ */
- OSErr FetchStatusString(unsigned short * statusReturn, Boolean papStatus, Boolean doRetry)
- /*
- Returns in statusString the current status for the printer. Returns various
- errors from IO package if the printer's status could not be found.
-
- Handles reporting error conditions to the user.
- */
- {
- OSErr anErr;
-
- anErr = DoTheQuery(statusReturn, papStatus);
- nrequire(anErr, Send_GXGetDeviceStatus);
-
- // printer offline?
- if (
- ( ((*statusReturn) & kPrinterOfflineMask) != 0 )
- )
- {
- gxStatusRecord theStat, *pStat = &theStat;
- Boolean printerIsFixed = false;
-
- pStat->statResId = kDriverStatus;
- pStat->statResIndex = kCheckOnline;
- pStat->bufferLen = 0;
- pStat->dialogResult = nil;
-
-
- // keep sending the user the alert until either
- // a) the problem resolves itself
- // b) the user responds via the dialog
- // c) some other (fatal) error happens
- do
- {
-
- // tell the user
- anErr = GXAlertTheUser(pStat);
-
- // if printer got suddenly turned online, do an OK
- if (doRetry)
- {
- (void) DoTheQuery(statusReturn, papStatus);
- if (
- ( ((*statusReturn) & kPrinterOfflineMask) == 0 )
- )
- {
- printerIsFixed = true;
- pStat->dialogResult = ok;
- anErr = noErr;
- }
- }
-
- } while ((anErr == noErr) && (pStat->dialogResult == nil));
-
- // based on the user's response, continue or cancel
- if (printerIsFixed)
- anErr = noErr;
- else
- anErr = gxPrUserAbortErr;
-
- // display "sending data to the printer" message
- if (anErr == noErr)
- anErr = GXReportStatus(kDriverStatus, kSendingData);
- }
-
- // FALL THROUGH EXCEPTION HANDLING
- Send_GXGetDeviceStatus:
-
- return(anErr);
-
- } // FetchStatusString
-
- //<FF>
- /* ------------------------------------------------------------------------------------ */
- OSErr UpdateConfiguration(void)
- /*
- This routine queries the printer for its hardware configuration (color ribbon and
- sheet feeder options), and stores that info into the configuration file.
- */
- {
- SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
- Str32 deviceName;
- OSErr anErr = noErr;
- ImageWriterConfigHandle configHandle;
- ImageWriterConfigPtr configPtr;
- Boolean isImageWriterII = false;
- ResType commType;
-
-
- // find out what we are printing to, and how we are connected
- GXGetPrinterName(GXGetJobOutputPrinter(GXGetJob()), deviceName);
- anErr = GXFetchDTPData(deviceName, gxDeviceCommunicationsType, gxDeviceCommunicationsID, (Handle*)&configHandle);
- nrequire(anErr, FetchCommType);
- commType = **(ResType**)configHandle;
- DisposHandle((Handle) configHandle);
-
-
- // store away the communications type for future use
- {
- SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
-
- (**hGlobals).commType = commType;
- }
-
- // find out the original configuration
- if (GXFetchDTPData(deviceName, kImageWriterConfigType, kImageWriterConfigID, (Handle*)&configHandle) == noErr)
- {
- // remember if we thought we had an IW2 when we started
- configPtr = *configHandle;
- (**hGlobals).isImageWriterII = isImageWriterII = configPtr->isImageWriterII;
- DisposeHandle((Handle) configHandle);
-
- // if we aren't an ImageWriter II, bail out now - because the timeout takes two minutes!
- if (!isImageWriterII)
- return(noErr);
- }
- else
- {
- // if we don't know yet, assume IW2 for PAP else Serial
- if (commType == 'PPTL')
- isImageWriterII = true;
-
- // Assume IW 2 so we do the query for real
- (**hGlobals).isImageWriterII = true;
- }
-
- // make a handle to hold our configuration information for the printer
- configHandle = (ImageWriterConfigHandle) NewHandle(sizeof(ImageWriterConfigRecord) );
- anErr = MemError();
- nrequire(anErr, NewHandle);
-
- // setup the default for the device - in case the query fails
- configPtr = *configHandle;
- configPtr->hasColorRibbon = false;
- configPtr->hasSheetFeeder = false;
- configPtr->isImageWriterII = true;
-
- {
- unsigned short statusReturn;
-
- // query the device
- anErr = FetchStatusString(&statusReturn, (commType == 'PPTL'), isImageWriterII);
-
- // and scan the string looking for information about printer kind and options
- configPtr = *configHandle;
- if ( anErr == gxAioTimeout )
- {
- // if we timeout and we don't know the printer kind - assume IW1
- if (!isImageWriterII)
- {
- anErr = noErr;
- isImageWriterII = configPtr->isImageWriterII = false;
- }
- }
- else
- {
- isImageWriterII = true;
- configPtr->hasColorRibbon = (statusReturn & (0x8000 >> kColorRibbonBit)) != 0;
- configPtr->hasSheetFeeder = (statusReturn & (0x8000 >> kSheetFeederBit)) != 0;
- }
- nrequire(anErr, FetchStatusString);
- }
-
- // Remember if this was an ImageWriter II after the query
- (**hGlobals).isImageWriterII = isImageWriterII;
-
- // write out the new configuration
- anErr = GXWriteDTPData(deviceName, kImageWriterConfigType, kImageWriterConfigID, (Handle)configHandle);
-
-
- // CLEANUP EXCEPTION HANDLING
- FetchStatusString:
- DisposHandle((Handle) configHandle);
-
- NewHandle:
- FetchCommType:
- return(anErr);
-
- } // UpdateConfiguration
-
-
- /* ------------------------------------------------------------------------------------ */
- OSErr WriteDraftChars(long **draftTable, unsigned char *draftChar, long numChars)
- /*
- This routine writes out a single character in the native set of the printer.
- It uses a table that's part of the driver to do the right thing in order to generate this
- character.
- */
- {
- OSErr anErr = noErr;
- char outputChars[20]; // a maximum of 20 characters can be generated
- short charCount;
-
- // For each character in the buffer, determine how to map the character to a draft character
- for (; numChars > 0; --numChars, ++draftChar)
- {
- // No characters yet for this output character
- charCount = 0;
-
- // Only consider characters in the printable range
- if (*draftChar >= 0x20)
- {
- unsigned long draftControl = (*draftTable)[*draftChar-0x20]; // Fetch native mode long word corresponding to this character
- unsigned char outChar;
- unsigned char nationalSet;
- short i;
-
- // For each word which composes the native mode long word
- for (i = 1; i >= 0; --i)
- {
- // Should we send a backspace character (to overstrike)?
- if ( (draftControl & 0x80000000) != 0 )
- outputChars[charCount++] = 0x08;
-
- outChar = (draftControl >> 16) & 0xFF;
- if (outChar != 0)
- {
- // Determine the national character set to select
- nationalSet = (draftControl >> 24) & 0xF;
-
- // Is this character in the standard, built-in character set?
- if (nationalSet == 0)
- {
- outputChars[charCount++] = outChar;
- }
- else // T => Must select a foreign language character set
- {
- outputChars[charCount++] = 0x1B;
- outputChars[charCount++] = 0x44;
- outputChars[charCount++] = nationalSet;
- outputChars[charCount++] = 0x00;
- outputChars[charCount++] = outChar;
- outputChars[charCount++] = 0x1B; // We always switch back to the kAmerican character set
- outputChars[charCount++] = 0x5A;
- outputChars[charCount++] = 0x07;
- outputChars[charCount++] = 0x00;
- }
- }
-
- // Take the next (low) word and process it (if we're not all done)
- draftControl <<= 16;
- }
- }
-
- // If we generated any data, send it out now
- if (charCount > 0)
- anErr = Send_GXBufferData(outputChars, charCount, gxNoBufferOptions);
- }
-
- return(anErr);
-
- } // WriteDraftChars
-
- /* ------------------------------------------------------------------------------------ */
- OSErr GetPointerThisBig(Ptr *theBuff, long numBytes)
- {
- OSErr anErr = noErr;
-
- if (*theBuff != nil)
- {
- if ( GetPtrSize(*theBuff) < numBytes ) // T => Won't be big enough; make a new one
- {
- DisposPtr(*theBuff);
- *theBuff = nil;
- }
- }
-
- if (*theBuff == nil)
- {
- *theBuff = NewPtrClear(numBytes);
- anErr = MemError();
- }
-
- return(anErr);
-
- } // GetPointerThisBig
-
- /* ------------------------------------------------------------------------------------ */
- OSErr GetTextAndPosition( gxShape theShape,
- Ptr *theChars,
- long *numChars,
- gxPoint *textPosition)
- {
- OSErr anErr = noErr;
- long textLength;
-
- // Determine the size of the text data and the position of the text
- textLength = GXGetLayout(theShape, nil, nil, nil, nil, nil, nil, nil, nil, textPosition);
-
- // Make sure we have a buffer pointer large enough to hold all of the data
-
- anErr = GetPointerThisBig(theChars, textLength);
- require(anErr == noErr, CantAllocTextBuff);
-
- // Now we retrieve the text
- GXGetLayout(theShape, *theChars, nil, nil, nil, nil, nil, nil, nil, nil);
-
- // Remember the number of characters in the shape
- *numChars = textLength;
-
-
- /******* Clean-up *******/
-
- CantAllocTextBuff:
- return(anErr);
-
- } // GetTextAndPosition
-
- /* ------------------------------------------------------------------------------------ */
- OSErr PrintPageInDraftMode(gxShape thePage, gxRasterImageDataHdl imageData)
- {
- OSErr anErr = noErr;
- long i;
- long numItems;
- Fixed currYPos = ff(0);
- Ptr theChars = nil;
- long numChars = 0;
- gxPoint textPosition;
- Fixed oldTextSize = ff(0);
- SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
-
- // Since the page picture we need to process is a picture shape that's embedded in
- // thePage (a shape containing one item => a picture), we need to extract the real
- // page picture from thePage.
-
- thePage = GetPictureItem(thePage, 1, nil, nil, nil, nil);
- numItems = GXGetPicture(thePage, nil, nil, nil, nil);
-
- // For each shape within the picture, check its type and process it accordingly
-
- for (i = 1; i <= numItems; ++i)
- {
- gxShape theShape;
- short theType;
-
- theShape = GetPictureItem(thePage, i, nil, nil, nil, nil);
- theType = GXGetShapeType(theShape);
-
- if (theType == gxLayoutType) // T => We have a layout shape
- {
- fixed textSize;
- char buff[12];
- char theFace;
- short cmndBuffSz;
-
- // First determine the style in which we're printing
-
- theFace = GetStyleCommonFace( GXGetShapeStyle(theShape) );
-
- buff[0] = ESCAPE;
- if ( (theFace & bold) != 0 ) // T => Turn bold facing on
- buff[1] = '!';
- else // T => Turn it off
- buff[1] = '"';
-
- buff[2] = ESCAPE;
- if ( (theFace & underline) != 0 ) // T => Turn underline facing on
- buff[3] = 'X';
- else // T => Turn it off
- buff[3] = 'Y';
-
- cmndBuffSz = 4;
-
- // Next determine if we need to change the size of the font being used
-
- textSize = GXGetShapeTextSize(theShape);
- if (textSize != oldTextSize) // T => Must issue LQ command to change font size
- {
- buff[4] = ESCAPE; // The first escape command selects black color
- buff[5] = kSetColorCommand;
- buff[6] = '0';
-
- buff[7] = ESCAPE; // The second escape command selects a draft font
- buff[8] = 'a';
- buff[9] = '1';
-
- buff[10] = ESCAPE; // The third escape command selects the character pitch
-
- if ( textSize <= ff(10) ) // T => Select 10 cpi
- {
- buff[11] = 'N';
- }
- else // T => All other sizes get mapped to 12 cpi
- {
- buff[11] = 'E';
- }
-
- // Remember the last text size
- oldTextSize = textSize;
-
- // Adjust the size of the data to be sent to the printer
- cmndBuffSz += 8;
- }
- // else - no change in font size
-
- // Send the commands to the printer
- anErr = Send_GXBufferData(buff, cmndBuffSz, gxDontSplitBuffer);
- require(anErr == noErr, CantSendFontCmnd);
-
- // Get the ASCII text and the starting position of the data
- anErr = GetTextAndPosition(theShape, &theChars, &numChars, &textPosition);
- require(anErr == noErr, CantGetTextAndPos);
-
- if ( (currYPos != ff(0)) && (currYPos != textPosition.y) ) // T => Moving to a lower line, finish the last ;line with a CR
- {
- char c = 0x0D;
-
- anErr = Send_GXBufferData(&c, 1, gxNoBufferOptions);
- require(anErr == noErr, CantSendCRCmnd);
- }
-
- // Position the print head to the proper location on the page
- {
- gxMapping theMapping;
- short lineFeedSize;
- Str255 positionCmndsBuff;
- unsigned long bytesInBuff = 0;
- char *p;
-
- GXGetShapeMapping(theShape, &theMapping);
- MapPoints(&theMapping, (long) 1, &textPosition); // Just map the first point
-
- // Now position the print head vertically
-
- lineFeedSize = (textPosition.y - currYPos) >> 16;
- anErr = Send_GXRasterLineFeed(&lineFeedSize, positionCmndsBuff, &bytesInBuff, imageData);
- require(anErr == noErr, CantEmitLineFeeds);
-
- // Update the current Y position pointer on the page
- currYPos = textPosition.y;
-
- // Now position the print head horizontally on the page
-
- p = &positionCmndsBuff[bytesInBuff];
- *p++ = ESCAPE;
- *p++ = 'F';
- Long2Dec((*hGlobals)->leftMargin + FixedToInt(textPosition.x), p); // Convert left margin into ASCII and place it at the start of the scan line
-
- // Update the number of bytes in the buffer
- bytesInBuff += 6;
-
- // Send the positioning info to the printer
- anErr = Send_GXBufferData(positionCmndsBuff, bytesInBuff, gxDontSplitBuffer);
- require(anErr == noErr, CantSendPositionCmnds);
- }
-
- // Now we send the text data to the printer
- anErr = WriteDraftChars((long **) (*hGlobals)->draftTable, theChars, numChars);
- require(anErr == noErr, CantWriteChars);
- }
- } // for
-
- // Send one last CR to wrap the last line (if there was one)
- {
- char c = 0x0D;
-
- anErr = Send_GXBufferData(&c, 1, gxNoBufferOptions);
- }
-
-
- /******* Clean-up *******/
-
- CantWriteChars:
- CantSendPositionCmnds:
- CantEmitLineFeeds:
- CantSendCRCmnd:
- CantGetTextAndPos:
- CantSendFontCmnd:
- if (theChars != nil)
- DisposPtr(theChars);
-
- return(anErr);
-
- } // PrintPageInDraftMode
-
- //<FF>
- /* ------------------------------------------------------------------------------------ */
- /* SPECIFIC DRIVER UNIVERSAL OVERRIDES */
- /* ------------------------------------------------------------------------------------ */
- OSErr SD_Initialize (void)
- /*
- The SD_Initalize message is called when a new job is created. The standard
- thing to do is to allocate and fill out your globals as you see fit.
- */
- {
-
- SpecGlobalsHdl hGlobals;
- OSErr anErr;
-
- // we make our globals
- hGlobals = (SpecGlobalsHdl) NewHandleClear( sizeof(SpecGlobals) );
- anErr = MemError();
-
- // and we save them away
- SetMessageHandlerInstanceContext(hGlobals);
-
- // is everything okay?
- nrequire(anErr, MNewHandleClear);
-
- // Don't need to initialize because of the NewHandleCLEAR
- //(**hGlobals).draftTable = nil;
- //(**hGlobals).lineFeeds = 0;
- //(**hGlobals).packagingOptions = kNoPackagingOptions;
-
- return(noErr);
-
-
- /*-----EXCEPTION HANDLING------*/
-
-
- MNewHandleClear:
- return(anErr);
-
- } // SD_Initialize
-
-
- //<FF>
- /* ------------------------------------------------------------------------------------ */
- OSErr SD_ShutDown(void)
- /*
- Shutdown is called when the job is done with. A good thing to do is to get
- rid of any additional storage that is laying around.
- */
- {
- // clean up our stuff
- SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
-
- // get rid of the draft table (if we have one);
- DisposHandle((**hGlobals).draftTable);
-
- // we get rid of our storage
- DisposHandle((Handle) hGlobals);
-
- // clear out our globals - to avoid double disposes
- SetMessageHandlerInstanceContext(nil);
-
- return(noErr);
-
-
- } // SD_ShutDown
-
- //<FF>
- /* ------------------------------------------------------------------------------------ */
- OSErr SD_DefaultPrinter(gxPrinter thePrinter)
- /*
- This call is made to setup the default printer object. The job of the
- specific driver is to add in any viewDevices that it wishes applications
- to be able to format specifically for.
- */
- {
- OSErr anErr;
- gxViewDevice vd;
- gxJob theJob = GXGetJob();
-
- // add the standard viewDevices first
- anErr = Forward_GXDefaultPrinter(thePrinter);
- nrequire(anErr, DefaultPrinter);
-
- // add a 144 b/w viewDevice
- vd = NewDeviceResolutionViewDevice();
- {
- gxSetColor theColors[2];
- gxSetColor *pColor;
- gxColorSet theSet;
-
- pColor = &theColors[0];
-
- pColor->rgb.red = pColor->rgb.green = pColor->rgb.blue = 0xFFFF;
-
- pColor++;
- pColor->rgb.red = pColor->rgb.green = pColor->rgb.blue = 0x0000;
-
- theSet = GXNewColorSet(gxRGBSpace, 2, theColors);
- SetViewDeviceColorSet(vd, theSet);
- GXDisposeColorSet(theSet);
- }
-
- anErr = GXAddPrinterViewDevice(thePrinter, vd);
- nrequire(anErr, FailedAddBWViewDevice);
-
-
- // add a 144 color viewDevice with 8 colors in it
- //
- // Color Index R G B
- // white 0 0xFFFF 0xFFFF 0xFFFF
- // yellow 1 0xFFFF 0xFFFF 0x0000
- // magenta 2 0xFFFF 0x0000 0xFFFF
- // red 3 0xFFFF 0x0000 0x0000
- // cyan 4 0x0000 0xFFFF 0xFFFF
- // green 5 0x0000 0xFFFF 0x0000
- // blue 6 0x0000 0x0000 0xFFFF
- // black 7 0x0000 0x0000 0x0000
-
- if (PrinterHasColorRibbon(thePrinter))
- {
- gxSetColor theColors[8];
- gxSetColor *pColor;
- gxColorSet theSet;
- short idx;
-
- vd = NewDeviceResolutionViewDevice();
-
- pColor = &theColors[0];
- for (idx = 0; idx < 8; ++idx)
- {
- // default the color to black
- pColor->rgb.red = pColor->rgb.green = pColor->rgb.blue = 0x0000;
-
- // and give it componants to go along with this index
- if (idx & 0x04)
- pColor->rgb.red = 0xFFFF;
- if (idx & 0x02)
- pColor->rgb.green = 0xFFFF;
- if (idx & 0x01)
- pColor->rgb.blue = 0xFFFF;
-
- // move on to the next color
- ++pColor;
- }
-
- theSet = GXNewColorSet(gxRGBSpace, 8, theColors);
- SetViewDeviceColorSet(vd, theSet);
- GXDisposeColorSet(theSet);
-
- anErr = GXAddPrinterViewDevice(thePrinter, vd);
- nrequire(anErr, FailedAddColorViewDevice);
- }
-
- /* Only if we are the output printer (not the formatting printer) */
- if (GXGetJobPrinter(theJob) == GXGetJobOutputPrinter(theJob)) {
- Collection jobCollection = GXGetJobCollection(GXGetJob());
- Handle jobQualitySettingsHdl;
- gxQualityInfo *qualitySettings;
- Ptr p;
- Str255 bestString, roughString;
-
- // read in our quality mode strings
- {
- short curResFile = CurResFile();
-
- UseResFile(GXGetMessageHandlerResFile());
-
- GetIndString( bestString, kNewQualityID, kBestString);
- GetIndString( roughString, kNewQualityID, kRoughString);
- UseResFile(curResFile);
- }
-
- jobQualitySettingsHdl = NewHandle(0);
- anErr = MemError();
- nrequire(anErr, FailedNewHandle);
-
- anErr = GetCollectionItemHdl ( jobCollection,
- gxQualityTag,
- gxPrintingTagID,
- jobQualitySettingsHdl );
-
- if (anErr == noErr)
- { /* Check for proper structure -- count as not found if different */
- HLockHi(jobQualitySettingsHdl);
-
- qualitySettings = *((gxQualityInfo **) jobQualitySettingsHdl);
- p = qualitySettings->qualityNames;
-
- if (qualitySettings->disableQuality)
- anErr = collectionItemNotFoundErr;
- else if (qualitySettings->qualityCount != 2)
- anErr = collectionItemNotFoundErr;
- else if (! IUEqualString(p, bestString))
- anErr = collectionItemNotFoundErr;
- else if (! IUEqualString(p + p[0] + 1, roughString))
- anErr = collectionItemNotFoundErr;
-
- HUnlock(jobQualitySettingsHdl);
- }
-
- if (anErr == collectionItemNotFoundErr)
- {
- Size count;
-
- /* Create the proper quality item */
- SetHandleSize(jobQualitySettingsHdl,(sizeof(gxQualityInfo) + bestString[0] + roughString[0] + 2 ));
- anErr = MemError();
- nrequire( anErr, FailedSetHandleSize );
-
- qualitySettings = *((gxQualityInfo **) jobQualitySettingsHdl);
-
- qualitySettings->disableQuality = false;
- qualitySettings->defaultQuality = 1;
- qualitySettings->currentQuality = 1;
- qualitySettings->qualityCount = 2;
-
- count = bestString[0]+1;
- p = qualitySettings->qualityNames;
- BlockMove( bestString, p, count );
-
- p += count;
- BlockMove( roughString, p, roughString[0]+1 );
-
- /* Add the proper quality item */
- anErr = AddCollectionItemHdl ( jobCollection,
- gxQualityTag,
- gxPrintingTagID,
- jobQualitySettingsHdl );
-
- /* Make it vilatile by driver */
- if (anErr == noErr)
- (void) SetCollectionItemInfo(jobCollection, gxQualityTag, gxPrintingTagID, 0x0000FFFF, gxVolatileOutputDriverCategory);
-
- }
-
- FailedSetHandleSize:
- DisposHandle(jobQualitySettingsHdl);
- }
- FailedNewHandle:
-
- ncheck(noErr);
- return(noErr);
-
-
-
- // EXCEPTION HANDLING
- FailedAddColorViewDevice:
- FailedAddBWViewDevice:
- GXDisposeViewDevice(vd);
-
- DefaultPrinter:
- return(anErr);
-
- } // SD_DefaultPrinter
-
- //<FF>
- /* ------------------------------------------------------------------------------------ */
-
- OSErr SD_DefaultFormat(gxFormat theFormat)
- {
- OSErr anErr;
- Handle jobQualitySettingsHdl;
-
- anErr = Forward_GXDefaultFormat(theFormat);
-
- // now, if the application has set up a special formatting mode, we need to update
- // the quality mode collection item (and any private ones we use)
- if (anErr == noErr)
- {
- gxPoint dpiPoint = {ff(72), ff(72)};
- gxMapping vdMapping;
- gxViewDevice selectedDevice = GXGetPrinterViewDevice(GXGetJobPrinter(GXGetFormatJob(theFormat)), 0);
-
- if (selectedDevice != GXGetPrinterViewDevice(GXGetJobPrinter(GXGetFormatJob(theFormat)), 1) )
- {
- GXGetViewDeviceMapping(selectedDevice, &vdMapping);
- MapPoints(&vdMapping, 1, &dpiPoint);
-
- {
- Collection jobCollection = GXGetJobCollection(GXGetJob());
- gxQualityInfo *qualitySettings;
-
- jobQualitySettingsHdl = NewHandle(0);
- anErr = MemError();
- nrequire(anErr, FailedNewHandle);
-
- anErr = GetCollectionItemHdl ( jobCollection,
- gxQualityTag,
- gxPrintingTagID,
- jobQualitySettingsHdl );
-
- nrequire(anErr, FailedGetCollectionItemHdl);
-
- qualitySettings = *((gxQualityInfo **) jobQualitySettingsHdl);
-
- qualitySettings->currentQuality =
- (dpiPoint.y > ff(100)) ? (qualitySettings->qualityCount-1) : 0;
-
- anErr = AddCollectionItemHdl ( jobCollection,
- gxQualityTag,
- gxPrintingTagID,
- jobQualitySettingsHdl );
-
- DisposHandle(jobQualitySettingsHdl);
- }
-
-
- if (anErr == noErr)
- {
- long formatOptions;
-
- // turn off super-res
- formatOptions = 0;
- anErr = AddCollectionItem(GXGetFormatCollection(theFormat),
- DriverCreator, 0,
- sizeof(formatOptions),
- &formatOptions);
- }
- }
- }
-
- FailedNewHandle:
- ncheck(anErr);
- return(anErr);
-
- FailedGetCollectionItemHdl:
- DisposHandle(jobQualitySettingsHdl);
- return(anErr);
-
- } // SD_DefaultFormat
-
- //<FF>
- /* ------------------------------------------------------------------------------------ */
- OSErr SD_DefaultJob()
- /*
- We override this message to add our default - highest res possible
- */
- {
- OSErr anErr;
-
- anErr = Forward_GXDefaultJob();
- if (anErr == noErr)
- {
- long imagewriterOptions = kSuperRes;
-
- anErr = AddCollectionItem(GXGetJobCollection(GXGetJob()),
- DriverCreator,
- 0,
- sizeof(imagewriterOptions),
- &imagewriterOptions);
-
- }
-
-
- return(anErr);
-
- } // SD_DefaultJob
-
- /* ------------------------------------------------------------------------------------ */
- OSErr SD_OpenConnection(void)
- /*
- The OpenConnection message is sent in order to open the connection to the device.
- */
- {
- OSErr anErr;
-
- // first, open the connection the standard way
- anErr = Forward_GXOpenConnection();
- nrequire(anErr, OpenConnection);
-
- // then, bring the configuration file up to date
- anErr = UpdateConfiguration();
- nrequire(anErr, UpdateConfiguration);
-
- return(noErr);
-
- // EXCEPTION HANDLING
- UpdateConfiguration:
- GXCleanupOpenConnection();
-
- OpenConnection:
-
- return(anErr);
-
- } // SD_OpenConnection
-
- /* ------------------------------------------------------------------------------------ */
- OSErr SD_CloseConnection(void)
- {
- unsigned short statusReturn;
- OSErr anErr, anErr2;
- ResType commType = (**(SpecGlobalsHdl)GetMessageHandlerInstanceContext()).commType;
-
- if (commType == 'PPTL')
- {
- // for PAP: wait for printer to finish printing so we can deal with the "out of paper case"
- do {
- anErr = FetchStatusString(&statusReturn, true, true);
- } while ((anErr == noErr) && ((statusReturn & kHeadMovingBit) != 0) );
- }
- else
- {
- // for serial: flush out all data so that we can query the printer properly one last time
- anErr = Send_GXWriteData(nil, 0);
- nrequire(anErr, Send_GXWriteData);
- }
-
- // one last time check up on printer status
- anErr2 = FetchStatusString(&statusReturn, (commType == 'PPTL'), true);
- if (anErr == noErr) anErr = anErr2;
-
- Send_GXWriteData:
- // close the connection the standard way
- anErr2 = Forward_GXCloseConnection();
- if (anErr == noErr) anErr = anErr2;
-
- return(anErr);
-
- } // SD_CloseConnection
-
- /* ------------------------------------------------------------------------------------ */
- OSErr SD_FreeBuffer(gxPrintingBuffer * theBuffer)
- {
- OSErr anErr;
- OSErr firstError = noErr;
-
- if ((**(SpecGlobalsHdl)GetMessageHandlerInstanceContext()).commType == 'PPTL')
- {
- unsigned short statusReturn;
- anErr = FetchStatusString(&statusReturn, true, true);
- nrequire(anErr, FetchStatusString);
- }
-
- do
- {
-
- // try to send the buffer again
- anErr = Forward_GXFreeBuffer(theBuffer);
- if (firstError == noErr)
- firstError = anErr;
-
- // timeout dialog!
- if (anErr == gxAioTimeout)
- {
- gxStatusRecord theStat, *pStat = &theStat;
-
- pStat->statResId = kDriverStatus;
- pStat->statResIndex = kCheckOnline;
- pStat->bufferLen = 0;
- pStat->dialogResult = nil;
-
- // tell the user to check the printer
- (void) GXAlertTheUser(pStat);
-
- // based on the user's response cancel
- if (pStat->dialogResult)
- anErr = gxPrUserAbortErr;
- }
-
- } while (anErr == gxAioTimeout);
-
- // put down the timeout dialog, if we ever put one up
- if (firstError != noErr)
- (void) GXReportStatus(kDriverStatus, kSendingData);
-
- FetchStatusString:
- return(anErr);
-
- } // SD_FreeBuffer
-
- /* ------------------------------------------------------------------------------------ */
- OSErr SD_DumpBuffer(gxPrintingBuffer * theBuffer)
- {
- OSErr anErr;
-
- if ((**(SpecGlobalsHdl)GetMessageHandlerInstanceContext()).commType == 'PPTL')
- {
- unsigned short statusReturn;
- anErr = FetchStatusString(&statusReturn, true, true);
- nrequire(anErr, FetchStatusString);
- }
- anErr = Forward_GXDumpBuffer(theBuffer);
-
- FetchStatusString:
- return(anErr);
-
- } // SD_DumpBuffer
-
- /* ------------------------------------------------------------------------------------ */
- OSErr SD_StartSendPage(gxFormat pageFormat)
- /*
- The StartSendPage message is sent just before the page begins to be rendered.
-
- Note that the StartSendPage message will not be sent until imaging/communication
- time, so that user interaction alerts are considered okay here
- */
- {
- OSErr anErr = noErr;
- gxJob theJob = GXGetJob();
- Collection jobCollection;
- gxPaperFeedInfo paperFeed;
- long itemSize = sizeof(paperFeed);
- ResType commType;
- unsigned short statusReturn;
-
- check(theJob);
- jobCollection = GXGetJobCollection(theJob);
- check(jobCollection);
-
- // cache communications type
- commType = (**(SpecGlobalsHdl)GetMessageHandlerInstanceContext()).commType;
- if (commType == 'PPTL')
- {
- anErr = FetchStatusString(&statusReturn, true, true);
- nrequire(anErr, FetchStatusString);
- }
- else
- statusReturn = 0;
-
- // first, check to see if the entire job is auto feed.
- paperFeed.autoFeed = true;
- (void) GetCollectionItem(jobCollection, gxPaperFeedTag, gxPrintingTagID, &itemSize, &paperFeed);
-
- // next, check to see if this particular page is to be manually fed
- if (!paperFeed.autoFeed)
- {
- // we now have the actual size of the paper feed item, so we get the manual feed list
- gxManualFeedInfo **feedHandle;
-
- feedHandle = (gxManualFeedInfo**) NewHandle(0);
- anErr = MemError();
- nrequire(anErr, FailedNewHandle);
-
- anErr = GetCollectionItemHdl(jobCollection, gxManualFeedTag, gxPrintingTagID, (Handle)feedHandle);
- if (anErr == noErr)
- {
- Str31 paperName;
- short idx;
- gxManualFeedInfo *pFeed;
-
- // name of this page's paper type
- GXGetPaperTypeName(GXGetFormatPaperType(pageFormat), paperName);
-
- // assume auto feed
- paperFeed.autoFeed = true;
-
- // lock and dereference for the loop
- HLockHi((Handle) feedHandle);
- pFeed = *feedHandle;
-
- // loop and see if one of our manual feed paperType's name matches
- for (idx = 0; idx < pFeed->numPaperTypeNames; ++idx)
- {
- Ptr pName = &pFeed->paperTypeNames[idx];
-
- if ( IUMagIDString( paperName,
- pName,
- paperName[0] + 1,
- *pName + 1) == 0 )
- {
- paperFeed.autoFeed = false;
- break;
- }
- }
- }
-
- DisposHandle((Handle) feedHandle);
- FailedNewHandle:
- ;
- }
-
- // manual feed or out of paper? Time to ask the user what to do
- if ( (!paperFeed.autoFeed)
- || ( ( (statusReturn & kOutOfPaperMask) != 0 ) )
- )
- {
- // Wait for all IO to complete, so that we can correctly tell the user what to do.
- // Since the WriteData message makes sure all data is flushed before performing the
- // IO, this call insures that pending IO is complete.
- anErr = Send_GXWriteData(nil, 0);
- nrequire(anErr, FlushAllData);
-
-
- // then, conduct the alert with the user
- {
- gxStatusRecord *pStat;
-
- // make a status record containing the request to the user - note that
- // we have to make room for ManualFeedRecord OR OutOfPaperRecord, but manual is bigger
- pStat = (gxStatusRecord *)NewPtrClear(sizeof(gxStatusRecord) + sizeof(gxManualFeedRecord));
- anErr = MemError();
- nrequire(anErr, NewPtrClear);
-
- pStat->statResId = gxUnivAlertStatusResourceId; // we use the built-in status for this
- pStat->dialogResult = nil;
-
- if (!paperFeed.autoFeed)
- {
- gxManualFeedRecord *pFeed;
-
- pStat->statResIndex = gxUnivManualFeedIndex; // status meaning "manual feed alert"
- pStat->bufferLen = sizeof(gxManualFeedRecord);
- pFeed = (gxManualFeedRecord*)&pStat->statusBuffer;
-
- // we can switch to autofeed if we want - and tell the user what kind of paper to load in
- pFeed->canAutoFeed = true;
- GXGetPaperTypeName(GXGetFormatPaperType(pageFormat), pFeed->paperTypeName);
- }
- else
- {
- gxOutOfPaperRecord *pOut;
-
- pStat->statResIndex = gxUnivOutOfPaperIndex; // status meaning "manual feed alert"
- pStat->bufferLen = sizeof(gxOutOfPaperRecord);
-
- pOut = (gxOutOfPaperRecord*)&pStat->statusBuffer;
- GXGetPaperTypeName(GXGetFormatPaperType(pageFormat), pOut->paperTypeName);
- }
-
- // keep sending the user the alert until either
- // a) the problem resolves itself
- // b) the user responds via the dialog
- // c) some other (fatal) error happens
- do
- {
-
- // tell the user
- anErr = GXAlertTheUser(pStat);
-
- // if the paper got suddenly loaded, do an OK
- if (commType == 'PPTL')
- {
- (void) FetchStatusString(&statusReturn, true, true);
- if ((statusReturn & kOutOfPaperMask) == 0)
- {
- pStat->dialogResult = ok;
- anErr = noErr;
- }
- }
-
- } while ((anErr == noErr) && (pStat->dialogResult == nil));
-
- // based on the user's response, continue, cancel, or switch to auto feed
- switch ( pStat->dialogResult )
- {
- case ok:
- // paper is loaded
- break;
-
- case cancel:
- // user wishes to stop the printing process
- anErr = gxPrUserAbortErr;
- break;
-
- case gxAutoFeedButtonId:
- // do rest of job with auto feed
- paperFeed.autoFeed = true;
- (void) AddCollectionItem(jobCollection, gxPaperFeedTag, gxPrintingTagID, itemSize, &paperFeed);
- break;
-
- } // switch
-
-
- // done with the status now
- DisposPtr((Ptr) pStat);
- }
-
- } // if manual feed job
-
- // display "sending data to the printer" message
- if (anErr == noErr)
- anErr = GXReportStatus(kDriverStatus, kSendingData);
-
- nrequire(anErr, FailedWaitForPaper);
-
- // continue with the standard starting of the page
- anErr = Forward_GXStartSendPage(pageFormat);
-
-
- // FALL THROUGH AND HANDLE EXCEPTIONS
-
- FailedWaitForPaper:
- NewPtrClear:
- FlushAllData:
- FetchStatusString:
- return(anErr);
-
- } // SD_StartSendPage
-
- /* ------------------------------------------------------------------------------------ */
- OSErr SD_FinishSendPage()
- {
- OSErr anErr = noErr;
- Str63 formLength; // should be more than big enough for form skipping
- char len = 0;
-
- // we may have issued line feeds RIGHT up to the end of the page. If
- // we do that and then issue a form feed, we'll kick out a blank page.
- // to avoid that, we back up a tad and then let the normal form feed
- // go through. Option 2 would be to track each and every motion control
- // we send to the printer -- but that's more work than this. In addition,
- // this method makes sure we are synced up exactly to the hardware
- formLength[len++] = ESCAPE;
- formLength[len++] = 'T';
- formLength[len++] = '0';
- formLength[len++] = '1';
- formLength[len++] = ESCAPE;
- formLength[len++] = 'r';
- formLength[len++] = 0x0A;
-
- // reset to forward motion for the form feed
- formLength[len++] = ESCAPE;
- formLength[len++] = 'f';
-
- anErr = Send_GXBufferData(&formLength[0], len, gxNoBufferOptions );
- nrequire(anErr, Send_GXBufferData);
-
- // Default implementation provides the actual form feed
- anErr = Forward_GXFinishSendPage();
-
- // FALL THROUGH EXCEPTION HANDLING
- Send_GXBufferData:
-
- return(anErr);
-
- } // SD_FinishSendPage
-
-
- /* ------------------------------------------------------------------------------------ */
- OSErr SD_FormatDialog(gxFormat theFormat, StringPtr title, gxDialogResult *theResult)
- /*
- This message is sent in response to the user's
- request to put up a page formatting dialog.
- */
- {
- OSErr err;
-
- err = NewMessageGlobals(A5Size(), A5Init);
- nrequire(err, NewMessageGlobals_Failed);
-
- err = SetupFormatPanel(r_FlipPanel2, theFormat);
- nrequire(err, CouldNotSetUpPanel);
-
- err = Forward_GXFormatDialog(theFormat, title, theResult);
- TearDownFormatPanel(*theResult, theFormat);
-
- CouldNotSetUpPanel:
- DisposeMessageGlobals();
-
- NewMessageGlobals_Failed:
- return err;
- }
-
-
- /* ------------------------------------------------------------------------------------ */
- OSErr SD_JobFormatDialog(gxDialogResult* theResult)
- /*
- This message is sent in response to the user's request to put up a formatting dialog
- */
- {
- OSErr anErr;
- gxJobFormatModeTableHdl theJobFormatModeList;
- long i;
- gxJob theJob = GXGetJob();
-
- anErr = NewMessageGlobals(A5Size(), A5Init);
- nrequire(anErr, NewMessageGlobals_Failed);
-
- anErr = SetupFormatPanel(r_FlipPanel, GXGetJobFormat(theJob, 1));
- nrequire(anErr, CouldNotSetUpPanel);
-
- // set up the JobFormatMode information
-
- anErr = GXGetAvailableJobFormatModes(&theJobFormatModeList);
- if ((!anErr) && (theJobFormatModeList))
- {
- for (i = 0; i <= (*theJobFormatModeList)->numModes - 1; ++i)
- {
- if ((*theJobFormatModeList)->modes[i] == gxTextJobFormatMode)
- {
- GXSetPreferredJobFormatMode(gxTextJobFormatMode, false);
- break;
- }
- }
- DisposHandle((Handle)theJobFormatModeList);
- }
-
- // do the normal dialogs after handling the job format mode stuff
- anErr = Forward_GXJobDefaultFormatDialog(theResult);
-
- TearDownFormatPanel(*theResult, GXGetJobFormat(theJob, 1));
-
- CouldNotSetUpPanel:
- DisposeMessageGlobals();
-
- NewMessageGlobals_Failed:
- return anErr;
-
- } // SD_JobFormatDialog
-
- /* ------------------------------------------------------------------------------------ */
- OSErr SD_JobFormatModeQuery( gxQueryType theQuery,
- void* srcData,
- void* dstData)
- /*
- This message is sent to find out information about the current job format mode.
- */
- {
- OSErr anErr = noErr;
- Handle theFonts;
- Handle theStyles;
-
- check(dstData != nil);
-
- // What type of query is being requested?
- switch(theQuery)
- {
- case gxSetStyleJobFormatCommonStyleQuery:
- {
- char *pStyleName;
-
- // Fetch the list of supported styles
-
- anErr = Send_GXFetchTaggedDriverData('STR#', kFormatModeStylesID, &theStyles);
- require(anErr == noErr, FailedToLoadStyles1);
-
- HNoPurge(theStyles);
- HLock(theStyles);
-
- // Determine which style is being referenced and set the corresponding style (only 2 styles
- // are currently supported)
-
- if (**((short **) theStyles) == 2) // T => We have the correct number of styles
- {
- char whichFace = 0;
-
- pStyleName = ((char *) *theStyles) + sizeof(short);
-
- if ( IUCompString(pStyleName, (char *) srcData) == 0 ) // T => They want bold face
- {
- whichFace = bold;
- }
- else
- {
- // Point to the next name in the list
- pStyleName += *pStyleName + 1;
-
- if ( IUCompString(pStyleName, (char *) srcData) == 0 ) // T => They want underline face
- {
- whichFace = underline;
- }
- }
-
- // If the client specified a valid face, set it now
- if (whichFace != 0)
- {
- SetStyleCommonFace((gxStyle) dstData, GetStyleCommonFace((gxStyle) dstData) | whichFace);
- }
- }
- // else - something is wrong with our resource
-
- // Dump the temporary handle
- DisposHandle(theStyles);
-
- break;
- }
-
- case gxGetJobFormatFontCommonStylesQuery:
- {
- short numStyles;
- short i;
- char *pStyleName;
-
- // Fetch the list of supported styles
-
- anErr = Send_GXFetchTaggedDriverData('STR#', kFormatModeStylesID, &theStyles);
- require(anErr == noErr, FailedToLoadStyles2);
-
- HNoPurge(theStyles);
- HLock(theStyles);
-
- // Determine the number of styles in the list
- numStyles = **((short **) theStyles);
-
- if (*(Handle *)dstData != nil) // T => Resize the handle to hold info. on the styles
- SetHandleSize(*(Handle *)dstData, sizeof(gxStyleNameTable) + ((numStyles - 1) * sizeof(Str255)));
- else
- *(Handle *)dstData = NewHandle(sizeof(gxStyleNameTable) + ((numStyles - 1) * sizeof(Str255)));
-
- anErr = MemError();
- require(anErr == noErr, StyleTableResizeFailed);
-
- // Now extract the name of each of the supported fonts
-
- for (i = 1, pStyleName = ((char *) *theStyles) + sizeof(short); i <= numStyles; ++i, pStyleName += *pStyleName + 1)
- {
- BlockMove(pStyleName, (*((gxStyleNameTableHdl) *(Handle *)dstData))->styleNames[i - 1], *pStyleName + 1);
- }
-
- (*((gxStyleNameTableHdl) *(Handle *)dstData))->numStyleNames = numStyles;
-
- // Dump the temporary handle
- DisposHandle(theStyles);
-
- break;
- }
-
- case gxGetJobFormatLineConstraintQuery: // This type of query is not supported
- if (*(Handle *)dstData != nil)
- SetHandleSize(*(Handle *)dstData, 0); // Don't return any data
- break;
-
- case gxGetJobFormatFontsQuery:
- {
- short numFonts;
- short i;
- char *pFontName;
-
- // Fetch the list of supported fonts
-
- anErr = Send_GXFetchTaggedDriverData('STR#', kFormatModeFontsID, &theFonts);
- require(anErr == noErr, FailedToLoadFonts);
-
- HNoPurge(theFonts);
- HLock(theFonts);
-
- // Determine the number of fonts in the list
- numFonts = **((short **) theFonts);
-
- if (*(Handle *)dstData != nil) // T => Resize the handle to hold info. on the fonts
- SetHandleSize(*(Handle *)dstData, sizeof(gxFontTable) + ((numFonts - 1) * sizeof(gxFont)));
- else
- *(Handle *)dstData = NewHandle(sizeof(gxFontTable) + ((numFonts - 1) * sizeof(gxFont)));
-
- anErr = MemError();
- require(anErr == noErr, FontTableResizeFailed);
-
- // Now generate a reference to each of the supported fonts
-
- for (i = 1, pFontName = ((char *) *theFonts) + sizeof(short); i <= numFonts; ++i, pFontName += *pFontName + 1)
- {
- gxFont thisFont;
- gxFontTable *pFontTable;
-
- thisFont = FindPNameFont(gxFullFontName, pFontName);
-
- pFontTable = *((gxFontTableHdl) *(Handle *)dstData);
- pFontTable->fonts[i - 1] = thisFont;
- }
-
- (*((gxFontTableHdl) *(Handle *)dstData))->numFonts = numFonts;
-
- // Dump the temporary handle
- DisposHandle(theFonts);
-
- break;
- }
-
- case gxGetJobFormatFontConstraintQuery:
- {
- gxPositionConstraintTable *pPositionTable;
-
- if ( *(Handle *)dstData != nil) // T => Resize the handle to hold info. on position constraints
- SetHandleSize(*(Handle *)dstData, sizeof(gxPositionConstraintTable) + sizeof(Fixed));
- else
- *(Handle *)dstData = NewHandle( sizeof(gxPositionConstraintTable) + sizeof(Fixed) );
-
- pPositionTable = *((gxPositionConstraintTableHdl) *(Handle *)dstData);
-
- pPositionTable->phase.x = 0; // Start at the top left corner of the page
- pPositionTable->phase.y = 0;
- pPositionTable->offset.x = ff(12); // Indent from the top left by a six lines per inch margin
- pPositionTable->offset.y = ff(12);
- pPositionTable->numSizes = 2; // Two font sizes supported
- pPositionTable->sizes[0] = ff(10); // 10 pitch
- pPositionTable->sizes[1] = ff(12); // 12 pitch
-
- break;
- }
- } // switch
-
- return(anErr);
-
-
- /******* Clean-up *******/
-
- StyleTableResizeFailed:
- DisposHandle((Handle) theStyles);
- return(anErr);
-
- FontTableResizeFailed:
- DisposHandle((Handle) theFonts);
-
- FailedToLoadStyles1:
- FailedToLoadStyles2:
- FailedToLoadFonts:
- return(anErr);
-
- } // SD_JobFormatModeQuery
-
- //<FF>
- /* ------------------------------------------------------------------------------------ */
- OSErr SD_SetupImageData(
- gxRasterImageDataHdl hImageData) // raster image data stuff
- /*
- This message is called to setup the constant data used for imaging the entire job.
- */
- {
-
- SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
- OSErr anErr;
- gxRasterImageDataPtr pImageData;
- Boolean isJobNotFinalQuality, isTextJobFormatMode;
- long imagewriterOptions;
-
- // do the default setup
- anErr = Forward_GXSetupImageData(hImageData);
- nrequire(anErr, Forward_GXSetupImageData);
-
- // test for 'final' quality mode
- isJobNotFinalQuality = !JobIsBest(&imagewriterOptions);
-
- // test for textJobFormatMode
- isTextJobFormatMode = ( GXGetJobFormatMode( GXGetJob() ) == gxTextJobFormatMode);
-
- // if the job is not final quality or using textJobFormatMode, downgrade the imaging data to our lower quality
- if (isJobNotFinalQuality || isTextJobFormatMode)
- {
- // ROUGH OR TEXT MODE
-
- // dereference for size and speed
- pImageData = *hImageData;
-
- // image at 80 or 72 dpi
- if (imagewriterOptions & kSuperRes)
- pImageData->hImageRes = ff(80);
- else
- pImageData->hImageRes = ff(72);
- pImageData->vImageRes = ff(72);
-
- // textJobFormatMode loads up the draft table, else setup halftones
- if (isTextJobFormatMode)
- {
- Handle draftTable;
-
- anErr = Send_GXFetchTaggedDriverData('idft', gxPrintingDriverBaseID, &draftTable);
- nrequire(anErr, FailedToLoadDraftTable);
-
- // store away the draft table
- (**hGlobals).draftTable = draftTable;
-
- // Download something?
- anErr = Send_GXFetchTaggedDriverData('idft', gxPrintingDriverBaseID+1, &draftTable);
- if (anErr == resNotFound)
- {
- draftTable = nil;
- anErr = noErr;
- }
- nrequire(anErr, GetDownloadTable);
-
- if (draftTable)
- {
- HLock(draftTable);
- anErr = Send_GXBufferData(*draftTable, GetHandleSize(draftTable), gxDontSplitBuffer);
- DisposHandle(draftTable);
- nrequire(anErr, SendDownloadTable);
- }
- }
- else
- {
- // use dither level that will look better at 72 dpi
- // resolution than our default values (MAYBE: 4 is the default now anyway)
- pImageData->theSetup.planeSetup[0].planeHalftone.method = 4;
-
- // of course, turn off color matching when in non-final mode!
- pImageData->theSetup.planeSetup[0].planeProfile = nil;
- }
-
- if (isJobNotFinalQuality)
- {
- if (imagewriterOptions & kSuperRes)
- {
- // use bidirectional instead of unidirectional
- // and also <esc>N instead of <esc>p for quality mode
- pImageData->packageControls.startPageStringID = gxPrintingDriverBaseID+3;
- }
- else
- {
- // use bidirectional instead of unidirectional
- // and also <esc>n instead of <esc>p for quality mode
- pImageData->packageControls.startPageStringID = gxPrintingDriverBaseID+2;
- }
- }
-
- // packaging data
- pImageData->packagingInfo.headHeight = 8; // 8 pins (instead of 16)
- pImageData->packagingInfo.numberPasses = 1; // in 1 head pass (instead of 2)
- pImageData->packagingInfo.passOffset = 0; // with no space between passes
- }
- else
- {
- // FINAL QUALITY
-
- // dereference for size and speed
- pImageData = *hImageData;
-
- // image at 160 or 144 dpi
- if (imagewriterOptions & kSuperRes)
- {
- pImageData->hImageRes = ff(160);
- pImageData->packageControls.startPageStringID = gxPrintingDriverBaseID+1;
- }
- else
- {
- pImageData->hImageRes = ff(144);
- pImageData->packageControls.startPageStringID = gxPrintingDriverBaseID+0;
- }
- }
-
- // not a color ribbon? Setup for black and white - do a B/W halftone rather than a dither
- if (!PrinterHasColorRibbon(GXGetJobOutputPrinter(GXGetJob())))
- {
- // dereference for size and speed
- pImageData = *hImageData;
-
- // one plane, no color flags, move the halftone info up into correct position
- pImageData->theSetup.planes = 1;
- pImageData->theSetup.depth = 1;
- pImageData->packagingInfo.colorPasses = 1;
- pImageData->packagingInfo.packageOptions = 0;
- pImageData->theSetup.planeSetup[0].planeSpace = gxNoSpace;
- pImageData->theSetup.planeSetup[0].planeSet = nil;
- pImageData->theSetup.planeSetup[0].planeProfile = nil;
- pImageData->theSetup.planeSetup[0].planeOptions = gxDefaultOffscreen;
- pImageData->theSetup.planeSetup[0].planeHalftone.method = gxRoundDot;
- pImageData->theSetup.planeSetup[0].planeHalftone.tintSpace = gxRGBSpace;
- }
-
- return(noErr);
-
- // EXCEPTION HANDLING
- SendDownloadTable:
- GetDownloadTable:
- DisposHandle((**hGlobals).draftTable);
- (**hGlobals).draftTable = nil;
-
- FailedToLoadDraftTable:
- Forward_GXSetupImageData:
- return(anErr);
-
- } // SD_SetupImageData
-
- /* ------------------------------------------------------------------------------------ */
- OSErr SD_FetchDriverData(
- ResType theType,
- short theID,
- Handle* theData)
- {
-
- OSErr anErr;
-
- anErr = Forward_GXFetchTaggedDriverData(theType, theID, theData);
-
- // do the translation at the proper DPI by modifying the old API
- // customization resource
- if ( (anErr == noErr) && // got the resource okay
- (theType == 'cust') && // it was a customization resource
- (theID == -8192) ) // with the old API id
- {
- long imagewriterOptions;
-
- if (!JobIsBest(&imagewriterOptions))
- {
- **((short**)theData) = 72;
- **((short**)theData+1) = 72;
- }
- }
-
- return(anErr);
-
- } // SD_FetchDriverData
-
-
- /* ------------------------------------------------------------------------------------ */
- OSErr SD_RenderPage( gxFormat theFormat,
- gxShape thePage,
- gxPageInfoRecord *pageInfo,
- gxRasterImageDataHdl imageInfo)
- /*
- The message sent to render an entire page.
- */
- {
-
- OSErr theError = noErr;
-
- // if not text mode, do it the normal (raster) way
- if (GXGetJobFormatMode(GXGetJob()) != gxTextJobFormatMode)
- {
- gxRectangle paperSize;
- Str63 formLength; // should be more than big enough for form skipping
- char aNumber[8];
- char len = 0;
- short formLen; // form length (in 144 dpi)
- short i;
-
-
- // find out how big our paper is
- GXGetPaperTypeDimensions(GXGetFormatPaperType(theFormat), nil, &paperSize);
-
- // determine the left margin (in pixels)
- {
- SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
- SpecGlobalsPtr pGlobals;
- gxRasterImageDataPtr pImageData;
-
- check(hGlobals);
-
- // dereference for size and speed
- pImageData = *imageInfo;
- pGlobals = *hGlobals;
- paperSize.left += ff(18); // ImageWriter's can't go tighter than .25 inch
- if (paperSize.left > 0)
- paperSize.left = 0;
- pGlobals->leftMargin = FixedToInt(
- FixMul(-paperSize.left,
- FixDiv(pImageData->hImageRes, ff(72))));
- }
-
- // move over the top margin, set the form length to be the size of the page
-
- // form length == top margin
- formLen = FixedToInt(FixMul(-paperSize.top, ff(2)) ); // length is set in 144 dpi
- if (formLen > 0)
- {
- // Forward line feed
- formLength[len++] = ESCAPE;
- formLength[len++] = 'f';
-
- // send multiples of 99
- if (formLen >= 99)
- {
- formLength[len++] = ESCAPE;
- formLength[len++] = 'T';
- formLength[len++] = '9';
- formLength[len++] = '9';
- while (formLen >= 99)
- {
- formLength[len++] = 0x0A; // line feed
-
- formLen -= 99;
- }
- }
-
- // send remaining line feeds
- if (formLen > 0)
- {
- formLength[len++] = ESCAPE;
- formLength[len++] = 'T';
- NumToString(formLen, aNumber);
- if (aNumber[0] == 1)
- {
- formLength[len++] = '0';
- formLength[len++] = aNumber[1];
- }
- else
- {
- formLength[len++] = aNumber[1];
- formLength[len++] = aNumber[2];
- }
- formLength[len++] = 0x0A; // line feed
- }
- }
-
- // form length == page size - top margin (which we already moved over)
- // BUT, since the top margin is a negative number we add it to the bottom
- // in order to subtract it
- formLength[len++] = ESCAPE;
- formLength[len++] = 'H';
- formLen = FixedToInt(FixMul(paperSize.bottom+paperSize.top, ff(2)) ); // length is set in 144 dpi
- NumToString(formLen, aNumber);
- for (i = 0; i < 4-aNumber[0]; ++i)
- formLength[len++] = '0';
- for (i = 1; i <= aNumber[0]; ++i)
- formLength[len++] = aNumber[i];
-
- // set this to be the top of form
- formLength[len++] = ESCAPE;
- formLength[len++] = 'v';
-
- // we've got all of this data, now send it
- theError = Send_GXBufferData(&formLength[0], len, gxNoBufferOptions );
- nrequire(theError, SetFormLength);
-
- // continue with normal rendering
- theError = Forward_GXRenderPage(theFormat, thePage, pageInfo, imageInfo);
- }
- else
- {
- theError = PrintPageInDraftMode(thePage, imageInfo);
- }
-
- failed_WrongShape:
- SetFormLength:
- return(theError);
-
- } // SD_RenderPage
-
-
- //<FF>
- /* ------------------------------------------------------------------------------------ */
- /* SPECIFIC DRIVER RASTER OVERRIDES */
- /* ------------------------------------------------------------------------------------ */
- OSErr SD_LineFeed (
- short *lineFeedSize, // amount to line feed by
- Ptr buffer, unsigned long * bufferPos, // data goes here
- gxRasterImageDataHdl hImageData) // raster image data stuff
- /*
- Message is sent to output paper advance commands to the printer
- */
- {
-
- OSErr anErr;
- Boolean amLowRes;
- short actualLineFeed = *lineFeedSize;
-
- amLowRes = ((**hImageData).vImageRes == ff(72));
- // if we are in low res mode, we double the line feed size, as all ImageWriter
- // line feed commands are expressed at 144 dpi.
- if (amLowRes)
- *lineFeedSize <<= 1;
-
- // optimize small motions (particularlly -1 followed by +1 with no data between)
- // into groups. This gets rid of the "paper dance" for blank colors passes.
- {
- SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
- SpecGlobalsPtr pGlobals = *hGlobals;
-
- if ( (pGlobals->packagingOptions == kDoSmallLineFeeds) ||
- (*lineFeedSize < -1) ||
- (*lineFeedSize > 1) )
- {
- *lineFeedSize += pGlobals->lineFeeds;
- pGlobals->lineFeeds = 0;
- // do the line feed in the default way
- anErr = Forward_GXRasterLineFeed(lineFeedSize, buffer, bufferPos, hImageData);
- }
- else
- {
- pGlobals->lineFeeds += *lineFeedSize;
- *lineFeedSize = 0;
- anErr = noErr;
- }
- }
-
- // and if in low quality mode, we divide the result to make up for the multiplication
- // that we do above
- if (amLowRes)
- *lineFeedSize >>= 1;
-
- return(anErr);
-
- } // SD_LineFeed
-
- //<FF>
- /* ------------------------------------------------------------------------------------ */
- OSErr SD_PackageBitmap (
- gxRasterPackageBitmapRec *pPackage,
- Ptr buffer, // data goes here + bufferPos
- unsigned long *bufferPos, // how much of the buffer already is full
- gxRasterImageDataHdl hImageData) // private image data
- /*
- Packages a bitmap for the ImageWriter
- This routine is called in order to add your rotated and packaged pixel
- data to the buffer. It is called once for each head pass. This routine
- is pretty complex because it also does IW run length compression.
-
- It must do the following:
-
- 1) Start filling the buffer from buffer+bufferPos. Remember
- that this pointer may not be word aligned - so be careful
- assigning things into it.
-
- 2) If your printer does SetMargins, put a "fake" set of commands at
- the begining of the data. Since most of the time you don't
- know the margins, you can save away the value of the bufferPos,
- and backpatch it after you have finished with the offscreen.
- SetMargins is used on printers that allow you to not send starting
- and ending whitespace.
-
- 3) Add in the rotated data for your printer. The data to stuff starts
- at location startY in hOffscreen. Stuff the bits from here until
- you reach startY+<your band size>, which is the size of your single
- band in this resolution mode. Increment your number by
- <your pass offset> + 1, which is the number of microspaces
- you will send between head passes to form this band. Take care
- that you don't step off of the end of the offscreen in this operation,
- you may be called with startY at the end of the offscreen if the first part
- of the band is white.
-
- colorBand contains the color band which you should be stuffing, from
- 1 to the number of color passes your printer needs (usually 4).
- Pack in the correct color band. The packager will call you once
- for each color band, and correctly handle line feeds and backward
- line feeds to do the correct thing. If your printer takes full
- RGB or CYMK data, I would define your number of colors to be
- 1 and pack the full RGB or CYMK data with the one call to StuffBuffers.
-
- If you request kSendAllColors in your raster pack resource, then this
- message will always be called for all color passes, even those that
- do not have data on them. For some printers, this is useful. For the
- case of the ImageWriter, this option is not specified, so this message
- will only be sent for colors that actually have dirty bits within them.
-
- 4) Backpatch SetMargins from your saved value in step 2) now that you
- know the margins.
-
- 5) Increment bufferPos by the number of bytes you have
- added to the buffer. Be sure to take into account the Set Margins
- command if you added one.
-
-
- */
- {
- #pragma unused (isColorDirty)
-
- OSErr anErr; // would you beleive we could make mistakes?
- ScanLinePtr pTheScanLine; // Pointer to the start of scan line data
- unsigned short lastDirtyCol; // Last dirty part of the scan line
- unsigned short firstDirty; // First dirty pixel
- unsigned short lastDirty; // Last dirty pixel
- Boolean bandIsDirty; // Is this band dirty?
- unsigned short numberBytesAdded;// Number of bytes we have added to the row
- unsigned short repeatCount; // Number of times we have seen this bitmap
-
- register unsigned short whichCol; // Index into the scan line data
- register unsigned short x,y; // Index values into the offscreen
-
- register Ptr thePtr; // Pointer to each Y scanline
- register unsigned char tempColumn; // Placeholder for the working column
- unsigned char lastColumn; // What was in the contents of the last column?
-
- Ptr basePtr; // Pointer to current X byte
- unsigned char outputMask; // Mask of bit to set in rotated image
- unsigned char inputMask; // Mask of bit to look at in X
- unsigned char startingInputMask;// Mask of first bit of interest
- unsigned short yPointerOffset; // Increment pointer by this to get to next scanline
-
- unsigned short endY, endX, incrY; // To remove loop invariants.
- unsigned short packingColor; // number of colors packing
- unsigned long originalBufferPos; // where we were in the buffer before we started;
- short originalLineFeeds; // how many line feeds did we have before?
- SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
- SpecGlobalsPtr pGlobals = *hGlobals;
-
- /* This macro stores one group into the pointer:
- P = Pointer to fill into
- G = Character for group
- S = Length of group run in pixels
- */
- #define EMITGROUP(P, G, S) \
- P->cEscape = ESCAPE; \
- P->cCommand = G; \
- Long2Dec(S, P->cLineLength);
-
- // save away original position in order to do a restore should the band be clean
- originalBufferPos = *bufferPos;
- originalLineFeeds = pGlobals->lineFeeds;
- if (originalLineFeeds == 0)
- {
- anErr = noErr;
- }
- else
- {
- // if we have any extra line feeds saved up, do them now!
- pGlobals->lineFeeds = 0;
- pGlobals->packagingOptions = kDoSmallLineFeeds;
- anErr = Send_GXRasterLineFeed(&originalLineFeeds, buffer, bufferPos, hImageData);
- pGlobals = *hGlobals;
- pGlobals->packagingOptions = kNoPackagingOptions;
- }
- nrequire(anErr, SendInitialLineFeeds);
-
- pTheScanLine = (ScanLinePtr) (buffer + kSetMarginsSize + (*bufferPos));
-
- /* Set color mode for this scan line, if needed */
- pTheScanLine->cColorEscape = ESCAPE;
- pTheScanLine->cSetColorCommand = kSetColorCommand;
-
- packingColor = (*hImageData)->packagingInfo.colorPasses;
- if (packingColor == 4)
- switch (pPackage->colorBand)
- {
- case 1: // yellow
- pTheScanLine->cColor = '1';
- startingInputMask = 0x10;
- break;
-
- case 2: // magenta
- pTheScanLine->cColor = '2';
- startingInputMask = 0x20;
- break;
-
- case 3: // cyan
- pTheScanLine->cColor = '3';
- startingInputMask = 0x40;
- break;
-
- case 4: // black
- pTheScanLine->cColor = '0';
- startingInputMask = 0x80;
- break;
-
- }
- else
- {
- pTheScanLine->cColor = '0';
- startingInputMask = 0x80;
- }
-
- /* Start with the first bit in the offscreen */
- inputMask = startingInputMask;
-
- /* We start out with no dirty bits */
- firstDirty = 0;
- lastDirty = 0;
- bandIsDirty = false;
-
- /* Set our array index to zero */
- whichCol = 0;
- lastDirtyCol = 0;
- numberBytesAdded = 0;
-
- /* Set up RLL variables */
- repeatCount = 0;
- lastColumn = 0;
-
- /* Get the byte pointer for the start of this color band */
- basePtr = pPackage->bitmapToPackage->image;
-
- /* Get the byte pointer for the start of the first scan line */
- basePtr += pPackage->startRaster * pPackage->bitmapToPackage->rowBytes;
-
- /* Save away loop invariants */
- endY = pPackage->startRaster + (*hImageData)->packagingInfo.headHeight; // Ending scan line
- incrY = (*hImageData)->packagingInfo.passOffset + 1; // Number of scanlines to increment by
- endX = pPackage->dirtyRect.right; // Ending X pos
- yPointerOffset = incrY * pPackage->bitmapToPackage->rowBytes; // amount to add to the input
- // pointer to move to the next scanline
-
- /* If the ending position is too large for the bitmap we have been given,
- truncate it, so that we don't print garbage */
- if (endY > pPackage->bitmapToPackage->height)
- endY = pPackage->bitmapToPackage->height;
-
- /* For the entire width of the offscreen, move a rolling mask along in the
- X direction, rotating up 8 bits of Y data per column. In addition, compress
- runs of columns that are > 14 length. */
- for (x = 0; x < endX; x++)
- {
- /* The bits in this column are clear to begin with */
- tempColumn = 0;
-
- /* Which byte to look at in the input buffer */
- thePtr = basePtr;
-
- /* Where to place the bit in the output. The ImageWriter takes the bit
- pattern upside down. */
- outputMask = 0x01;
-
- /* Scan through this band, setting each of the 8 bits == the bit in that scan line */
- for (y = pPackage->startRaster; y < endY; y += incrY)
- {
- /* If we have a bit in the input, rotate it into the output */
- if ((*thePtr) & inputMask)
- tempColumn |= outputMask;
-
- // move onto next position in the output data
- outputMask <<= 1;
-
- // move onto the next scan line in the input data
- thePtr += yPointerOffset;
- } // for y
-
-
- /* Save the column info */
- pTheScanLine->iTheData[whichCol] = tempColumn;
-
- /* Get the next bit from the current pointer */
- inputMask >>= packingColor;
- if (!inputMask)
- {
- /* If we run out of bits, get the next byte */
- basePtr++;
-
- /* And reset the bit mask to the first bit */
- inputMask = startingInputMask;
- }
-
- /* If we have some form of data */
- if (tempColumn != 0)
- {
- if (!bandIsDirty)
- {
- /* This is the first dirty pixels we have so far */
- bandIsDirty = true;
- firstDirty = x;
- }
-
- /* This is also the last dirty pixels so far */
- lastDirty = x;
- } // SetDirty
-
- /* If we have some dirty bits */
- if (bandIsDirty)
- {
- /* Move on to the next column */
- whichCol++;
-
- /* If this is a dirty column, then it is the last one so far */
- if (tempColumn != 0)
- lastDirtyCol = whichCol;
-
- /* If we have a duplication, up the repeat count */
- if (tempColumn == lastColumn) // if (false) // turn off repeat groups
- {
- repeatCount++;
- if (repeatCount == 14)
- {
- /* Kick out the old group */
- whichCol -= 14;
- EMITGROUP(pTheScanLine, kGraphicsCommand, whichCol);
- numberBytesAdded += whichCol + kGroupSize;
- pTheScanLine = (ScanLinePtr)(((Ptr) pTheScanLine) +
- whichCol + kGroupSize);
-
- whichCol = 1;
- lastDirtyCol = 1;
- pTheScanLine->iTheData[0] = tempColumn;
- }
- }
- else
- {
- /* If we were repeating, emit the repeat group */
- if (repeatCount >= 14)
- {
- EMITGROUP(pTheScanLine, kRepeatGroup, repeatCount);
- numberBytesAdded += 1 + kGroupSize;
- pTheScanLine = (ScanLinePtr) (((Ptr) pTheScanLine) +
- 1 + kGroupSize);
-
- whichCol = 1;
- lastDirtyCol = 1;
- pTheScanLine->iTheData[0] = tempColumn;
- }
- repeatCount = 0;
- lastColumn = tempColumn;
- }
-
- } // BandIsDirty
-
- } // end of loop for width of bitmap
-
- /* if we have a dirty band - emit the final bit of data we have
- packaged up */
- if (bandIsDirty)
- {
-
- /* Set the margins to be the first and last dirty pixels in the scan line -
- the ImageWriter only does left margin optimization. */
- {
- SetMarginsPtr marginBuffer;
- SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
-
- check(hGlobals);
-
- /* Get the location for placing the set margin command */
- marginBuffer = (SetMarginsPtr) (buffer + (*bufferPos));
-
- /* Stuff in the set margin command */
- marginBuffer->cEscape = ESCAPE;
- marginBuffer->cCommand = kSetMarginsCommand;
-
- /* convert left margin into ASCII and place it at the start of the buffer */
- Long2Dec((**hGlobals).leftMargin + firstDirty, (Ptr)(marginBuffer->cIndentDistance));
- }
-
- /* Send the last group command */
- if (repeatCount < 14)
- {
- /* Emit a normal group */
- EMITGROUP(pTheScanLine, kGraphicsCommand, lastDirtyCol);
- numberBytesAdded += lastDirtyCol + kGroupSize;
- }
- else
- {
- /* Don't stuff a final repeat group if it's blank space */
- if (tempColumn != 0)
- {
- /* Emit a repeat group */
- EMITGROUP(pTheScanLine, kRepeatGroup, repeatCount);
- numberBytesAdded += 1 + kGroupSize;
- }
- } // end of repeatCount < 14
-
-
- /* Increment the count of the buffer by bytes added for groups, plus
- the header, if any, plus the set margins command */
- (*bufferPos) += numberBytesAdded + kScanLineSize + kSetMarginsSize;
-
- /* and put a <cr> at the end of the line */
- *(char*)(buffer + (*bufferPos)) = '\n';
- (*bufferPos) += 1;
-
- } // bandIsDirty
- else
- {
- // don't output data if we didn't have any!
- *bufferPos = originalBufferPos;
-
- // restore original number of line feeds
- pGlobals = *hGlobals;
- pGlobals->lineFeeds = originalLineFeeds;
- } // band is not dirty
-
- // always return your errors!
- SendInitialLineFeeds:
- return(anErr);
-
- } // SD_PackageBitmap
-
-
-
-
- // SD_DespoolPage is an override for GXDespoolPage. In here, we flip the
- // transform of our page shapes, if that's what the user specified in our
- // options dialog.
-
- OSErr SD_DespoolPage(gxSpoolFile aSpoolFile, long pageNum, gxFormat pageFormat,
- gxShape *thePage, Boolean *formatChanged)
- {
- OSErr err;
- gxFlipPageHorizontalInfo hFlipInfo;
- gxFlipPageVerticalInfo vFlipInfo;
- long itemSize;
- gxMapping pgMapping;
- gxRectangle pageSize, paperSize;
- char flipVar;
-
- // First, forward the message so that we get the final page shape.
-
- err = Forward_GXDespoolPage(aSpoolFile, pageNum, pageFormat, thePage,
- formatChanged);
-
- nrequire(err, Despool_Failed);
-
-
- // Now, see if the user said to flip the page horizontally or vertically.
- // If the flipping tags arn't present, we'll assume that means "don't flip."
- // If we're not flipping, return from the routine.
-
- itemSize = sizeof(gxFlipPageHorizontalInfo);
-
- err = GetFmtCollectionItem(&hFlipInfo, &itemSize, gxFlipPageHorizontalTag,
- gxPrintingTagID, pageFormat);
-
- if (err) hFlipInfo.flipHorizontal = false;
-
- itemSize = sizeof(gxFlipPageVerticalInfo);
-
- err = GetFmtCollectionItem(&vFlipInfo, &itemSize, gxFlipPageVerticalTag,
- gxPrintingTagID, pageFormat);
-
- if (err)
- {
- vFlipInfo.flipVertical = false;
- err = noErr;
- }
-
- require((hFlipInfo.flipHorizontal || vFlipInfo.flipVertical), NoFlipping);
-
-
- // We store a 1,2, or 3 in flipVar, which allows us to use a switch statement
- // to determine the correct flipping to do. Next, we get the format's
- // dimensions and the shape's mapping, which will be used to flip the image.
-
- flipVar = (char) hFlipInfo.flipHorizontal + 2* (char) vFlipInfo.flipVertical;
-
- GXGetFormatDimensions(pageFormat, &pageSize, &paperSize);
- GXGetShapeMapping(*thePage, &pgMapping);
-
-
- // This next part is a little obscure, but if you picture a paperType, we
- // want to translate the origin from one corner of the page to another, and
- // then scale negatively (which does the actual flipping). For the horizontal
- // flip, we need to move the origin to its horizontally opposite corner, and
- // for a vertical flip, we need to move the origin to its vertically opposite
- // corner. (This means that horizontal flipping causes the origin to move
- // from the top/left corner to the top/right one, and for vertical flipping
- // it moves to the bottom/left corner.) If vertical and horizontal flipping
- // are combined, then the two actions are combined. Note that you need to do
- // the origin translation, since the negative scaling would make your shape
- // live outside of the bounds of the pageArea otherwise, which would cause it
- // to be clipped.
-
- switch (flipVar)
- {
- case 1: // horizontal only.
- MoveMapping(&pgMapping, -paperSize.left -pageSize.right, 0);
- ScaleMapping(&pgMapping, ff(-1), ff(1), 0, 0);
- break;
-
- case 2: // vertical only.
- MoveMapping(&pgMapping, 0, -paperSize.top -pageSize.bottom);
- ScaleMapping(&pgMapping, ff(1), ff(-1), 0, 0);
- break;
-
- case 3: // horizontal and vertical.
- MoveMapping(&pgMapping, -paperSize.left -pageSize.right, -paperSize.top -pageSize.bottom);
- ScaleMapping(&pgMapping, ff(-1), ff(-1), 0, 0);
- break;
- }
-
- // Finally, set the shape's mapping and return.
-
- GXSetShapeMapping(*thePage, &pgMapping);
-
- NoFlipping:
- Despool_Failed:
- return err;
- }
-
-
- // ToggleControl toggles a control on or off. It's useful for controls
- // like checkboxes or radio buttons, which can only have a value of 0
- // or 1. The function takes a "void **" so that we don't have to
- // typecast the handle returned from GetDItem before calling this routine.
-
- void ToggleControl(void **itemH)
- {
- short ctlVal = GetCtlValue((ControlHandle) itemH);
-
- ctlVal = (ctlVal == 1)? 0: 1;
- SetCtlValue((ControlHandle) itemH, ctlVal);
- }
-
-
-
- /*******************************************************************
- SD_HandlePanelEvent is our override for GXHandlePanelEvent. If
- the event is one of ours, we handle it, otherwise we just
- forward it down the chain.
-
- ********************************************************************/
-
- OSErr SD_HandlePanelEvent(gxPanelInfoRecord *panelInfo)
- {
- OSErr err = noErr;
- GrafPtr oldPort;
- DialogPtr pDlg;
- short theItem, itemKind, ctlVal;
- Rect itemRect;
- Handle itemHdl;
-
- // Get a pointer to the dialog, save our current grafPort,
- // and set us to the dialog's port.
-
- pDlg = panelInfo->pDlg;
- GetPort(&oldPort);
- SetPort(pDlg);
-
- switch (panelInfo->panelEvt)
- {
- case gxPanelOpenEvt:
- // Light up our checkboxes, as appropriate.
-
- GetDItem(pDlg, panelInfo->itemCount +d_pHFlip, &itemKind, &itemHdl, &itemRect);
- ctlVal = (gFlippedPicts->curFlipping & 0x01)? 1:0;
- SetCtlValue((ControlHandle) itemHdl, ctlVal);
- GetDItem(pDlg, panelInfo->itemCount +d_pVFlip, &itemKind, &itemHdl, &itemRect);
- ctlVal = (gFlippedPicts->curFlipping & 0x02)? 1:0;
- SetCtlValue((ControlHandle) itemHdl, ctlVal);
- break;
-
- case gxPanelHitEvt:
- // If it's a hit in our checkboxes, process.
-
- theItem = panelInfo->itemHit -panelInfo->itemCount;
-
- if ((theItem == d_pHFlip) || (theItem == d_pVFlip))
- {
- GetDItem(pDlg, panelInfo->itemHit, &itemKind, &itemHdl, &itemRect);
- ToggleControl(itemHdl);
- gFlippedPicts->curFlipping = GetCurFlip(pDlg, d_pHFlip +panelInfo->itemCount, d_pVFlip +panelInfo->itemCount);
-
- GetDItem(pDlg, panelInfo->itemCount +d_FlipPict,
- &itemKind, &itemHdl, &itemRect);
-
- InvalRect(&itemRect);
- }
-
- break;
- }
-
- // Restore the original port as we leave.
-
- SetPort(oldPort);
- return err;
- }
-
-
- /*******************************************************************
- SD_FilterPanelEvent is a routine to filter update events in our
- panel, and update our userItems accordingly.
-
- ********************************************************************/
-
- OSErr SD_FilterPanelEvent(gxPanelInfoRecord *panelInfo, Boolean *returnImmed)
- {
- OSErr err = noErr;
- DialogPtr pDlg;
-
- #pragma unused(returnImmed);
-
- // Get a pointer to the dialog, save our current grafPort,
- // and set us to the dialog's port.
-
- pDlg = panelInfo->pDlg;
-
- switch (panelInfo->panelEvt)
- {
- case gxPanelFilterEvt:
-
- switch (panelInfo->theEvent->what)
- {
- case updateEvt: // look for, and handle, our update events.
-
- if ((WindowPtr) panelInfo->theEvent->message == pDlg)
- err = HandlePanelUpdate(pDlg, panelInfo);
-
- break;
- }
- break;
- }
-
- return err;
- }
-
-
- /*******************************************************************
- HandlePanelUpdate is a routine to update our panel's userItems.
- Note that we don't pass this routine to the Dialog Manager,
- we only get here by way of our panel event handler. This
- assures that we can access our global data, and that our
- resource file is open. In this example, we draw from a global
- PicHandle, to show that our globals are intact.
-
- NOTE: With the exception of the code below that's marked:
-
- "YOU SHOULD CHANGE THE FOLLOWING…"
-
- you can just use this code verbatim, regardless of the number
- or purpose of your dialog's userItems.
-
- ********************************************************************/
-
- OSErr HandlePanelUpdate(DialogPtr theDialog, gxPanelInfoRecord *panelInfo)
- {
- GrafPtr oldPort;
- OSErr err;
- Rect theClipRect, myUserItemRect;
- RgnHandle tempRgn, oldVis;
- Point top;
- short dx, dy, itemKind;
- Handle itemHdl;
-
- // Create a new region handle. If we can't do that, return an error.
-
- tempRgn = NewRgn();
- require_action(tempRgn, CanNotCreateRgn, err = MemError(););
-
-
- // Copy the window's update region to our temporary region handle,
- // then adjust the region so that it's correctly aligned with our
- // window. Finally, intersect this region with the window's visRgn.
-
- CopyRgn(((DialogPeek) theDialog)->window.updateRgn, tempRgn);
- top = *(Point *) &(*tempRgn)->rgnBBox.top;
- GlobalToLocal(&top);
- dx = (*tempRgn)->rgnBBox.left - top.h;
- dy = (*tempRgn)->rgnBBox.top - top.v;
- OffsetRgn(tempRgn, -dx, -dy);
- SectRgn(theDialog->visRgn, tempRgn, tempRgn);
-
- nrequire((err = MemError()), CanNotCopyRgn);
-
-
- // Now, get the boundsRect of our userItem and see if
- // any falls within the update area. If not, don't
- // bother drawing anything.
-
- GetDItem(theDialog, panelInfo->itemCount + d_FlipPict, &itemKind,
- &itemHdl, &myUserItemRect);
-
- theClipRect = (*tempRgn)->rgnBBox;
-
- if (SectRect(&myUserItemRect, &theClipRect, &theClipRect))
- {
-
- // Save the current visRgn, and store our temporary region as the new
- // visRgn. This is similar to what happens when BeginUpdate is called.
- // When we draw, only pixels that fall in the update area (clipped to
- // the window's clipRgn) will be drawn. This keeps us from doing
- // unnecessary redrawing, which would cause flashing and wasted cycles.
-
- oldVis = theDialog->visRgn;
- theDialog->visRgn = tempRgn;
-
-
- // Save the current port, change it to the dialog's port, draw any
- // userItems that need updating, validate their areas and restore
- // the old visRgn and grafPort.
-
- GetPort(&oldPort);
- SetPort(theDialog);
-
- // Draw picture like old code.
-
- DrawPicture(gFlippedPicts->pict[gFlippedPicts->curFlipping], &myUserItemRect);
- InsetRect(&myUserItemRect, -1, -1);
- FrameRect(&myUserItemRect);
- ValidRect(&myUserItemRect);
-
- theDialog->visRgn = oldVis;
- SetPort(oldPort);
- }
-
- // Throw away our temporary region, and return any error.
-
- CanNotCopyRgn:
- DisposeRgn(tempRgn);
-
- CanNotCreateRgn:
- return err;
- }
-